
#include <iostream>
#include <poll.h>
#include <sys/time.h>
#include "Socket.hpp"

using namespace std;
static const uint16_t defaultport = 8888;
static const int fd_num_max = 64; // 监听文件描述符最大个数
int defaultfd = -1;
int non_event = 0;
class PollServer
{
public:
    PollServer(uint16_t port = defaultport) : _port(port)
    {
        for (int i = 0; i < fd_num_max; i++)
        {
            _event_fds[i].fd = defaultfd;
            _event_fds[i].events = non_event; // 位图数据结构，需要关心的事件初始化为0
            _event_fds[i].revents = non_event;
            // std::cout << "fd_array[" << i << "]" << fd_array[i] << std::endl;
        }
    }
    bool Init()
    {
        _listensock.Socket();    // 创建套接字
        _listensock.Bind(_port); // 绑定套接字
        _listensock.Listen();
        return true;
    }
    void Accepter()
    {
        // 连接已就绪，开始处理
        std::string clientip;
        uint16_t clientport = 0;
        // accept
        int sock = _listensock.Accept(&clientip, &clientport);
        if (sock < 0)
            return;
        lg(Info, "3.accept success ,%s:%d,sock为：%d", clientip.c_str(), clientport, sock);
        cout << "4.listen.fd为：" << _listensock.Fd() << endl;
        // 把sock套接字添加进辅助数组，从1开始遍历辅助数组，因为0是监听套接字
        int pos = 1;
        for (; pos < fd_num_max; pos++)
        {
            // 被设置过
            if (_event_fds[pos].fd != defaultfd)
                continue;
            else
                cout << "5.没有被设置过的位置值为-1，所以当前_event_fds[pos].fd" << _event_fds[pos].fd << endl;
            break; // fd_array[pos]等于defaultfd，说明该位置没有被设置文件描述符过，break，准备使用该位置记录accept的套接字
        }
        // 如果for循环走完了，走到最后一个位置，说明辅助数组全被设置过，位置占满了
        if (pos == fd_num_max)
        {
            // 位置占满了，关闭当前accept的套接字
            lg(Warning, "server is full,close %d now!", sock);
            close(sock);

            // 扩容
        }
        else
        {
            // 新获取到的连接向数组空位置添加
            cout << "6.新获取到的连接向数组空位置添加" << endl;
            _event_fds[pos].fd = sock;
            _event_fds[pos].fd = POLLIN;
            _event_fds[pos].revents = non_event;
            PrintFD();
        }
        cout << "7.执行到这里，Accepter函数接收连接逻辑完成,接收套接字为： " << sock << endl;
    }
    void Recver(int fd, int pos)
    {
        char buffer[1024];
        cout << "read开始阻塞等待，当前套接字为：" << fd << endl;
        ssize_t n = read(fd, buffer, sizeof(buffer) - 1); // bug?
        if (n > 0)
        {
            buffer[n] = 0;
            cout << "get a message:" << buffer << endl;
        }
        else if (n == 0) // 读到0，对方把文件描述符关了
        {
            lg(Info, "client quit, me too,close fd is: ", fd);
            // 服务端也要关闭该文件描述符
            close(fd);
            _event_fds[pos].fd = defaultfd; // 从select读集合中移除该文件描述符
        }
        else
        {
            lg(Warning, "recv error: fd is: %d", fd);
            close(fd);
            _event_fds[pos].fd = defaultfd;
        }
    }
    // 监听到一个新连接，处理
    void Dispatcher()
    {
        cout << "1.已经进入事件派发器" << endl;
        // 已经就绪的位图在rfds里
        for (int i = 0; i < fd_num_max; i++)
        {
            cout << "i请更新:" << i << endl;
            int fd = _event_fds[i].fd; // 得到指定文件描述符
            // cout << "fd值为：" << fd << endl;
            if (fd == defaultfd)
                continue;

            // 位图形式按位与，判断读事件是否就绪
            if (_event_fds[i].revents & POLLIN)
            {
                // 我是监听套接字并且我已经就绪
                if (fd == _listensock.Fd())
                {
                    cout << "2.fd == _listensock.Fd(),准备进入连接管理器,fd值为： " << fd << endl;
                    Accepter(); // 来连接管理器
                    cout << "accept执行完后，i应该++,所以i的值是：" << i << endl;
                }
                // fd != _listensock.Fd()，其他文件描述符就绪，其他文件描述符可以读
                else
                {
                    cout << "fd != _listensock.Fd(),执行接收处理函数";
                    Recver(fd, i);
                }
            }
            cout << "if循环外查看是否运行到这" << endl;
        }
        cout<<"for循环外查看是否执行到"<<endl;
    }
    void Start()
    {
        _event_fds[0].fd = _listensock.Fd();
        _event_fds[0].events = POLLIN; // 题型OS关心读事件是否就绪，监听连接到来本质是读事件就绪
        int timeout = 3000;            // 3s
        for (;;)
        {
            int n = poll(_event_fds, fd_num_max, timeout);
            cout << "已经执行完poll函数" << endl;
            switch (n)
            {
            case 0:
                cout << "time out,timeout:" << endl;
                break;
            case -1:
                cerr << "Select error" << endl;
                break;
            default:
                // 有事件就绪,如果不处理这份连接，底层会一直通知上层“已经获取到连接”
                cout << "get a new link" << endl;
                // 事件派发器
                Dispatcher(); // 哪个文件描述符的连接（读）事件就绪信息保存在rfds变量里
                break;
            }
        }
    }
    void PrintFD()
    {
        cout << "online fd list: ";
        for (int i = 0; i < fd_num_max; i++)
        {
            if (_event_fds[i].fd == defaultfd)
            {
                continue;
            }
            cout << _event_fds[i].fd << " ";
        }
        cout << endl;
    }
    ~PollServer()
    {
        _listensock.Close();
    }

private:
    Sock _listensock; // 定义一个Sock类型对象，这个类型已做好套接字的封装
    uint16_t _port;
    struct pollfd _event_fds[fd_num_max];
};
